package xyz.xtt.pay.service.impl;

import static xyz.xtt.pay.service.impl.Asset1155BuyPayOrderOperator.SECOND_TRADE_SPLIT_ACCOUNT_PERCENTAGE;
import static xyz.xtt.pay.service.impl.Asset1155BuyPayOrderOperator.SPLIT_ACCOUNT_PERCENTAGE;
import static xyz.xtt.pay.utils.AssertUtils.isFalse;
import static xyz.xtt.pay.utils.AssertUtils.isNull;

import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;
import com.google.common.primitives.Longs;

import cn.hutool.core.thread.ThreadFactoryBuilder;
import cn.hutool.core.util.IdUtil;
import cn.hutool.json.JSONUtil;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Positive;
import lombok.extern.slf4j.Slf4j;
import xyz.xtt.asset.api.enums.GoodsTypeEnum;
import xyz.xtt.asset.api.enums.OwnerTypeEnum;
import xyz.xtt.asset.api.enums.RocketMessageDelayLevelEnum;
import xyz.xtt.asset.api.enums.SecondEnum;
import xyz.xtt.asset.client.request.CancelTransactionRequest;
import xyz.xtt.asset.client.request.ConfirmTransactionRequest;
import xyz.xtt.asset.client.response.AssetInfoResponse;
import xyz.xtt.asset.client.response.AssetTransactionResponse;
import xyz.xtt.asset.client.response.TransactionResponse;
import xyz.xtt.asset.support.BusinessOrderOperatorFactory;
import xyz.xtt.common.starter.cache.CacheManager;
import xyz.xtt.pay.api.dto.GetPayStatusMapRequest;
import xyz.xtt.pay.api.dto.GetPayStatusRequest;
import xyz.xtt.pay.api.dto.PayAttach;
import xyz.xtt.pay.api.dto.SplitAccountItem;
import xyz.xtt.pay.api.enums.PayOrderBusinessTypeEnum;
import xyz.xtt.pay.api.enums.PayOrderStatusEnum;
import xyz.xtt.pay.client.request.ConfirmPayOrderRequest;
import xyz.xtt.pay.client.request.MakeOrderRequest;
import xyz.xtt.pay.constants.ErrorMessage;
import xyz.xtt.pay.dto.OrderRefundMessage;
import xyz.xtt.pay.dto.PayCenterOrderStatusResponse;
import xyz.xtt.pay.dto.PayDelayMessage;
import xyz.xtt.pay.dto.pay.GoodsInfo;
import xyz.xtt.pay.dto.pay.PayNotifyRequest;
import xyz.xtt.pay.entity.TblBusinessOrder;
import xyz.xtt.pay.entity.TblPayOrder;
import xyz.xtt.pay.entity.TblPayOrderLog;
import xyz.xtt.pay.entity.TblPayOrderRefundRecord;
import xyz.xtt.pay.enums.DealStateEnum;
import xyz.xtt.pay.enums.OrderTypeEnum;
import xyz.xtt.pay.enums.PayOrderRefundStatusEnum;
import xyz.xtt.pay.exception.ChainException;
import xyz.xtt.pay.service.BusinessOrderOperator;
import xyz.xtt.pay.service.IInnerService;
import xyz.xtt.pay.service.INftOrderService;
import xyz.xtt.pay.service.IPayOrderOperator;
import xyz.xtt.pay.service.IRocketMqService;
import xyz.xtt.pay.service.ITblBusinessOrderService;
import xyz.xtt.pay.service.ITblPayOrderLogService;
import xyz.xtt.pay.service.ITblPayOrderRefundRecordService;
import xyz.xtt.pay.service.ITblPayOrderService;
import xyz.xtt.pay.support.PayCenterHttpService;
import xyz.xtt.pay.support.PayCenterV3HttpService;
import xyz.xtt.pay.support.PayOrderOperatorFactory;
import xyz.xtt.pay.utils.RedisLockUtil;
import xyz.xtt.pay.vo.CreateOrderRequest;
import xyz.xtt.pay.vo.PayCallbackMessage;
import xyz.xtt.pay.vo.PayCenterArgsResponse;
import xyz.xtt.pay.vo.PayCenterArgsResponseV3;
import xyz.xtt.pay.vo.PayContinueRequest;
import xyz.xtt.pay.vo.paycenter.PayOrderCancelRequest;
import xyz.xtt.pay.vo.paycenter.PayOrderStatusChangeResponse;
import xyz.xtt.user.client.response.UserInfoResponse;

/**
 * 支付单服务实现
 *
 * @author dale
 * @date 2025/1/13
 **/
@Slf4j
@Service
@RefreshScope
public class NftOrderServiceImpl implements INftOrderService {

	private static final String PAY_ORDER_DELAY_MQ_TAG = "PayOrderDelay";
	private static final int PAY_CENTER_ORDER_STATE_NOT_PAY = 2;
	private static final int CORE_THREAD_COUNT = Runtime.getRuntime().availableProcessors() * 2 + 1;
	private static final ThreadFactory THREAD_FACTORY = new ThreadFactoryBuilder().setNamePrefix("pay-order-service-thread-%d").build();
	private static final ThreadPoolExecutor EXECUTOR = new ThreadPoolExecutor(
			CORE_THREAD_COUNT, CORE_THREAD_COUNT, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(20), THREAD_FACTORY,
			new ThreadPoolExecutor.CallerRunsPolicy());

	@Autowired
	private IInnerService iInnerService;
	@Autowired
	private PayCenterHttpService payCenterHttpService;
	@Autowired
	private PayCenterV3HttpService payCenterV3HttpService;
	@Autowired
	private RedisLockUtil redisLockUtil;
	@Autowired
	private IRocketMqService rocketMqService;
	@Autowired
	private CacheManager cacheManager;
	@Autowired
	private ITblPayOrderService iTblPayOrderService;
	@Autowired
	private ITblPayOrderLogService iTblPayOrderLogService;
	@Autowired
	private ITblPayOrderRefundRecordService tblPayOrderRefundRecordService;
	@Autowired
	private BusinessOrderOperatorFactory businessOrderOperatorFactory;
	@Autowired
	private ITblBusinessOrderService iTblBusinessOrderService;
	@Value("${pay.order.cancel.delay.gap:30}")
	private int cancelPayOrderGap;
	@Value("${rocketmq.producer.paydealy}")
	private String orderDelayTopic;
	@Value("${auth.check.switch:true}")
	private boolean checkAuthSwitch;
	@Value("${auth.check.frequency:1440}")
	private Integer authCheckFrequency;
	@Value("${personal.mint.order.price}")
	private String personalMintPrice;
	@Value("${pay.order.delay.message.level:16}")
	private Integer payOrderDelayMessageLevel;
	@Value("${pay.order.function.enable:true}")
	private boolean canOperatePay;
	@Value("${pay.order.function.enable.userIds}")
	private Set<String> canOperatePayUserIds;
	@Value("${pay.order.test.reset.price.userIds}")
	private Set<String> resetPriceTestUserIds;
	// 赠送上限
	@Value("${asset.gift.send.limit:3}")
	private Long giftSendLimit;
	// 接收上限
	@Value("${asset.gift.recv.limit:3}")
	private Long giftRecvLimit;
	@Value("${pay.center.version:v2}")
	private String payCenterVersion;
	@Value("${spring.profiles.active}")
	private String profileActive;
	@Value("${skip.real.pay:false}")
	private boolean skipRealPay;
	@Value("${pay.back.url:https://nft-h5.xtt.xyz/pay/result}")
	private String payBackUrl;

	@Autowired
	private StringRedisTemplate stringRedisTemplate;
	@Autowired
	private PayOrderOperatorFactory payOrderOperatorFactory;

	/**
	 * 前端创建订单
	 *
	 * @param uid
	 * @param request
	 * @return
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public PayCenterArgsResponse createPayOrder(@NotNull String uid, @Valid CreateOrderRequest request, GoodsInfo goodsInfo) {
		// 初步校验
		UserInfoResponse user = iInnerService.userInfo(Long.valueOf(uid));
		isFalse(user != null && Objects.equals(user.getStatus(), 0), ErrorMessage.USER_STATUS_EX);
		isFalse(user.getAuthBefore() != null, ErrorMessage.NEED_AUTHENTICATION);
		if (request.getPurchaseAmount() <= 0) {
			throw new ChainException(ErrorMessage.ARGUMENT_NOT_VALID);
		}
		// 检查支付功能是否可用
		if (!canOperatePay(uid)) {
			throw new ChainException(ErrorMessage.PAY_FUNCTION_NOT_ENABLE);
		}

		// 根据不同的订单类型，调用不同的处理方法
		PayOrderBusinessTypeEnum orderTypeEnum = PayOrderBusinessTypeEnum.getByName(request.getOrderType());
		IPayOrderOperator orderOperator = payOrderOperatorFactory.getOperator(orderTypeEnum);
		if (orderOperator == null) {
			throw new ChainException(ErrorMessage.UN_SUPPORTED_ORDER_TYPE);
		}
		return orderOperator.createPayOrder(user, orderTypeEnum, request, goodsInfo);
	}

	/**
	 * 判断是否有效的订单类型
	 *
	 * @param orderTypeEnum
	 * @return
	 */
	private boolean isValidOrderType(PayOrderBusinessTypeEnum orderTypeEnum) {
		return Objects.equals(PayOrderBusinessTypeEnum.NORMAL, orderTypeEnum) || Objects.equals(PayOrderBusinessTypeEnum.PERSONAL_MINT, orderTypeEnum)
				|| Objects.equals(PayOrderBusinessTypeEnum.PERSONAL_MINT_V2, orderTypeEnum)
				|| Objects.equals(PayOrderBusinessTypeEnum.NFT_VIP_MONTH, orderTypeEnum)
				|| Objects.equals(PayOrderBusinessTypeEnum.NFT_VIP_SEASON, orderTypeEnum)
				|| Objects.equals(PayOrderBusinessTypeEnum.NFT_VIP_YEAR, orderTypeEnum) || Objects.equals(PayOrderBusinessTypeEnum.ROSE_MINT, orderTypeEnum);
	}

	@Override
	public void sendPayDelayMessage(TblPayOrder payOrder) {
		log.info("sendPayDelayMessage payOrder:{}", payOrder);
		PayDelayMessage payDelayMessage = PayDelayMessage.builder().payOrderId(payOrder.getPayOrderId()).buyUserId(payOrder.getAppUserId()).build();
		rocketMqService
				.sendDelayedMessage(orderDelayTopic, PAY_ORDER_DELAY_MQ_TAG, JSONUtil.toJsonStr(payDelayMessage), RocketMessageDelayLevelEnum
						.convert(payOrderDelayMessageLevel));
	}

	/**
	 * 保存自动支付成功订单
	 *
	 * @param businessTypeEnum
	 * @param businessRefId
	 * @param price
	 * @param appUserId
	 * @return
	 */
	@Override
	public long saveAutoSuccessPayOrder(PayOrderBusinessTypeEnum businessTypeEnum, String businessRefId, BigDecimal price, Long appUserId) {
		long timestamp = System.currentTimeMillis();
		TblPayOrder payOrder = TblPayOrder
				.builder()
				.payOrderId(IdUtil.getSnowflakeNextId())
				.businessType(businessTypeEnum.getCode())
				.businessRefId(businessRefId)
				.appUserId(appUserId)
				.payStatus(PayOrderStatusEnum.PAY_SUCCESS.getCode())
				.payMoney(price)
				.orderMoney(price)
				.createTime(timestamp)
				.updateTime(timestamp)
				.build();
		iTblPayOrderService.save(payOrder);

		TblPayOrderLog payOrderLog = TblPayOrderLog
				.builder()
				.payOrderId(payOrder.getPayOrderId())
				.payOrderLogId(IdUtil.getSnowflakeNextId())
				.payStatus(PayOrderStatusEnum.PAY_SUCCESS.getCode())
				.createTime(timestamp)
				.build();
		iTblPayOrderLogService.save(payOrderLog);
		return payOrder.getPayOrderId();
	}

	@Override
	public TblPayOrder saveUnPayOrder(AssetTransactionResponse assetTransaction, PayOrderBusinessTypeEnum businessTypeEnum, String businessRefId,
			BigDecimal payMoney, AssetInfoResponse asset) {
		PayAttach payAttach = new PayAttach(assetTransaction.getAssetId(), asset.getGoodsId());
		return this.saveUnPayOrder(assetTransaction, businessTypeEnum, businessRefId, payMoney, payAttach);
	}

	@Override
	public TblPayOrder saveUnPayOrder(AssetTransactionResponse assetTransaction, PayOrderBusinessTypeEnum businessTypeEnum, String businessRefId,
			BigDecimal payMoney, PayAttach payAttach) {
		long timestamp = System.currentTimeMillis();
		TblPayOrder payOrder = TblPayOrder
				.builder()
				.payOrderId(IdUtil.getSnowflakeNextId())
				.businessType(businessTypeEnum.getCode())
				.businessRefId(businessRefId)
				.appUserId(Long.valueOf(assetTransaction.getBuyerUserId()))
				.payStatus(PayOrderStatusEnum.UN_PAY.getCode())
				.payMoney(payMoney)
				.orderMoney(payMoney)
				.createTime(timestamp)
				.updateTime(timestamp)
				.businessAttach(JSONUtil.toJsonStr(payAttach))
				.build();
		iTblPayOrderService.save(payOrder);

		TblPayOrderLog payOrderLog = TblPayOrderLog
				.builder()
				.payOrderId(payOrder.getPayOrderId())
				.payOrderLogId(IdUtil.getSnowflakeNextId())
				.payStatus(PayOrderStatusEnum.UN_PAY.getCode())
				.createTime(timestamp)
				.build();
		iTblPayOrderLogService.save(payOrderLog);
		return payOrder;
	}

	@Override
	public TblPayOrder saveUnPayOrder(PayOrderBusinessTypeEnum businessTypeEnum, String businessRefId, BigDecimal payMoney, Long buyerUserId) {
		return saveUnPayOrder(businessTypeEnum, businessRefId, payMoney, buyerUserId, null);
	}

	@Override
	public TblPayOrder saveUnPayOrder(PayOrderBusinessTypeEnum businessTypeEnum, String businessRefId, BigDecimal payMoney, Long buyerUserId,
			String businessAttach) {
		long timestamp = System.currentTimeMillis();
		TblPayOrder payOrder = TblPayOrder
				.builder()
				.payOrderId(IdUtil.getSnowflakeNextId())
				.businessType(businessTypeEnum.getCode())
				.businessRefId(businessRefId)
				.appUserId(buyerUserId)
				.payStatus(PayOrderStatusEnum.UN_PAY.getCode())
				.payMoney(payMoney)
				.orderMoney(payMoney)
				.businessAttach(businessAttach)
				.createTime(timestamp)
				.updateTime(timestamp)
				.build();
		iTblPayOrderService.save(payOrder);

		TblPayOrderLog payOrderLog = TblPayOrderLog
				.builder()
				.payOrderId(payOrder.getPayOrderId())
				.payOrderLogId(IdUtil.getSnowflakeNextId())
				.payStatus(PayOrderStatusEnum.UN_PAY.getCode())
				.createTime(timestamp)
				.build();
		iTblPayOrderLogService.save(payOrderLog);
		return payOrder;
	}

	/**
	 * 支付延迟消息处理
	 *
	 * @param payDelayMessage 消息
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public void payDelayCancel(PayDelayMessage payDelayMessage) {
		Long payOrderId = payDelayMessage.getPayOrderId();
		if (payOrderId == null) {
			log.warn("payDelayCancel skip. payOrderId is null");
			return;
		}

		String lockKey = String.format(RedisLockUtil.LOCK_KEY_PAY_ORDER, payOrderId);
		String lockValue = UUID.randomUUID().toString();
		boolean locked = false;
		try {
			locked = redisLockUtil.tryLock(lockKey, lockValue, 1, TimeUnit.MINUTES, 3, TimeUnit.SECONDS);
			if (locked) {
				TblPayOrder payOrder = iTblPayOrderService.getPayOrder(payOrderId, payDelayMessage.getBuyUserId());
				if (Objects.isNull(payOrder)) {
					log.warn("payDelayCancel skip. payOrder is null. payOrderId:{}", payOrderId);
					return;
				}
				PayOrderStatusEnum payOrderStatusEnum = PayOrderStatusEnum.getByCode(payOrder.getPayStatus());
				if (payOrderStatusEnum.canUpdateTo(PayOrderStatusEnum.PAY_CANCEL)) {
					// 取消业务交易
					payOrderOperatorFactory.getOperator(PayOrderBusinessTypeEnum.getByCode(payOrder.getBusinessType())).doPayCancel(payOrder, "超时取消");
				} else {
					log.warn("payDelayCancel skip. payOrder can not be canceled. payOrder:{}", JSONUtil.toJsonStr(payOrder));
				}
			} else {
				throw new RuntimeException("payDelayCancel failed. acquire lock failed. payOrderId:" + payOrderId);
			}
		} finally {
			if (locked) {
				redisLockUtil.releaseLock(lockKey, lockValue);
			}
		}
	}

	/**
	 * 取消支付订单
	 *
	 * @param payOrder
	 */
	private void doPayCancel(TblPayOrder payOrder, String remark) {
		// 取消关联业务交易
		if (Objects.equals(payOrder.getBusinessType(), PayOrderBusinessTypeEnum.NORMAL.getCode())
				|| Objects.equals(payOrder.getBusinessType(), PayOrderBusinessTypeEnum.PERSONAL_MINT.getCode())) {
			TransactionResponse transaction = iInnerService
					.queryPaySyncOne(String.valueOf(payOrder.getAppUserId()), Longs.tryParse(payOrder.getBusinessRefId()));
			CancelTransactionRequest cancelTransactionRequest = CancelTransactionRequest
					.builder()
					.orderId(Long.valueOf(payOrder.getBusinessRefId()))
					.from(Long.valueOf(transaction.getSellerUserId()))
					.to(Long.valueOf(transaction.getBuyerUserId()))
					.assetId(transaction.getAssetId())
					.build();
			iInnerService.cancelTransaction(cancelTransactionRequest);
		}

		// 取消payOrder
		TblPayOrderLog payOrderLog = TblPayOrderLog
				.builder()
				.payOrderLogId(IdUtil.getSnowflakeNextId())
				.payStatus(PayOrderStatusEnum.PAY_CANCEL.getCode())
				.payOrderId(payOrder.getPayOrderId())
				.createTime(System.currentTimeMillis())
				.detail(remark)
				.build();
		isFalse(iTblPayOrderLogService.save(payOrderLog), ErrorMessage.ORDER_OPERATE_FAILED);

		isFalse(iTblPayOrderService
				.updatePayStatus(payOrder.getPayOrderId(), PayOrderStatusEnum.UN_PAY, PayOrderStatusEnum.PAY_CANCEL), ErrorMessage.ORDER_OPERATE_FAILED);
		// 发送支付订单状态变更消息
		rocketMqService.sendPayOrderStatusChangeMsg(payOrder.getPayOrderId());
	}

	/**
	 * 支付回调消费
	 *
	 * @param callbackMessage 回调消息
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public void payCallbackConsume(PayCallbackMessage callbackMessage, boolean innerInvoke) {
		log.info("payCallbackConsume 开始处理支付or退款结果回调 callbackMessage:{}", callbackMessage);

		// 判断是支付完成还是退款完成
		boolean isRefund = Objects.equals(callbackMessage.getIsRefund(), 1);
		String appUserId = callbackMessage.getUserId();
		String payOrderId = callbackMessage.getOrderNo();

		// 订单级别分布式锁同步
		String lockKey = String.format(RedisLockUtil.LOCK_KEY_PAY_ORDER, Long.valueOf(payOrderId));
		String lockValue = UUID.randomUUID().toString();
		boolean locked = false;
		try {
			locked = redisLockUtil.tryLock(lockKey, lockValue, 1, TimeUnit.MINUTES, 10, TimeUnit.SECONDS);
			if (!locked) {
				log.warn("订单 {} 分布式锁同步失败", payOrderId);
				throw new RuntimeException("订单支付同步失败");
			}

			TblPayOrder payOrder = iTblPayOrderService.getPayOrder(Long.valueOf(payOrderId), Long.valueOf(appUserId));
			if (Objects.isNull(payOrder)) {
				log.warn("payCallbackConsume skiped 没有找到目标订单 {}", payOrderId);
				return;
			}
			PayOrderBusinessTypeEnum payOrderBusinessTypeEnum = PayOrderBusinessTypeEnum.getByCode(payOrder.getBusinessType());
			IPayOrderOperator payOrderOperator = payOrderOperatorFactory.getOperator(payOrderBusinessTypeEnum);
			if (payOrderOperator == null) {
				log.error("支付处理失败，目标订单类型不支持！ {}", JSONUtil.toJsonStr(callbackMessage));
				return;
			}

			if (!isRefund) {
				// 尝试补充第三方支付订单id、支付渠道信息
				if (StringUtils.isBlank(payOrder.getPayTradeNo()) && StringUtils.isNotBlank(callbackMessage.getThirdTradeNo())) {
					tryUpdatePayTradeAttr(payOrder, callbackMessage);
				}

				// 处理支付中心支付完成情况
				PayOrderStatusEnum curPayStatus = PayOrderStatusEnum.getByCode(payOrder.getPayStatus());
				if (Objects.equals(curPayStatus, PayOrderStatusEnum.PAY_CANCEL)) {
					// 订单已取消后接收到支付成功消息。比如用户停留在收银台页面超过30分钟后再进行支付会导致该情况发生。此时应该
					if (alreadyApplyRefund(payOrder.getPayOrderId())) {
						log.warn("支付中心支付成功，业务订单已取消，已申请退款 {}", JSONUtil.toJsonStr(callbackMessage));
					} else {
						startRefundOrder(payOrder, callbackMessage);
					}
				} else if (curPayStatus.canUpdateTo(PayOrderStatusEnum.PAY_SUCCESS)) {
					// 二次校验订单状态
					PayCenterOrderStatusResponse orderStatusResponse = refreshPayOrderStatus(payOrder.getPayOrderId(), callbackMessage.getUserId(), payOrder
							.getOrderMoney(), payOrder.getBusinessAttach());
					if (orderStatusResponse == null) {
						throw new RuntimeException("获取订单支付状态失败：payOrderId:" + payOrderId);
					} else if (!Objects.equals(orderStatusResponse.getState(), 1)) {
						log.error("收到支付成功MQ但订单查询接口未返回支付成功。payOrderId:{},orderStatusResponse:{}", payOrderId, JSONUtil.toJsonStr(callbackMessage));
						if (!skipRealPay()) {
							return;
						}
					}
					// 资产交易记录确认
					payOrderOperator.confirmPayOrder(payOrder, callbackMessage, appUserId);
				} else {
					log.warn("支付处理失败，目标订单不是待支付状态！ callbackMessage:{} currentStatus:{}", JSONUtil.toJsonStr(callbackMessage), payOrder.getPayStatus());
				}

			} else if (Objects.equals(payOrder.getPayStatus(), PayOrderStatusEnum.PAY_SUCCESS.getCode())) {
				// 处理退款成功消息（目前程序未发出退款，暂不处理退款消息）
				log.error("接收到退款成功消息 {}", JSONUtil.toJsonStr(callbackMessage));
			} else {
				log.warn("退款处理失败，目标订单不是已支付状态！ {}", JSONUtil.toJsonStr(callbackMessage));
			}

		} finally {
			if (locked) {
				redisLockUtil.releaseLock(lockKey, lockValue);
			}
		}
	}

	@Override
	public boolean skipRealPay() {
		return skipRealPay && (Objects.equals(profileActive, "develop") || Objects.equals(profileActive, "test"));
	}

	private PayCenterOrderStatusResponse refreshPayOrderStatus(Long payOrderId, String userId, BigDecimal orderMoney, String businessAttach) {
		boolean isV3 = false;
		String prepayId = null;
		if (StringUtils.isNotBlank(businessAttach)) {
			PayAttach payAttach = JSONUtil.toBean(businessAttach, PayAttach.class);
			if (payAttach != null && Objects.equals(payAttach.getPayCenterVersion(), "v3")) {
				isV3 = true;
				isNull(payAttach.getPrepayId(), ErrorMessage.UNKNOWN_ERROR, () -> {
					log.error("payAttach.prepayId is null.payOrderId:{}", payOrderId);
				});
				prepayId = payAttach.getPrepayId();
			}
		}

		if (isV3) {
			return payCenterV3HttpService.queryPayStatus(payOrderId, userId, prepayId);
		} else {
			return payCenterHttpService.queryPayOrderStatus(payOrderId, userId, orderMoney);
		}
	}

	/**
	 * 尝试补充第三方支付订单id、支付渠道信息
	 *
	 * @param payOrder
	 * @param callbackMessage
	 */
	private void tryUpdatePayTradeAttr(TblPayOrder payOrder, PayCallbackMessage callbackMessage) {
		UpdateWrapper<TblPayOrder> updateWrapper = new UpdateWrapper<>();
		updateWrapper.eq("pay_order_id", payOrder.getPayOrderId());
		updateWrapper.set("pay_trade_no", callbackMessage.getThirdTradeNo());
		updateWrapper.set("pay_mode", callbackMessage.getPayMode());
		updateWrapper.set("pay_mode_sub", callbackMessage.getPayModeSub());
		iTblPayOrderService.update(updateWrapper);
	}

	private boolean canOperateBusinessType(Integer businessType) {
		PayOrderBusinessTypeEnum payOrderBusinessTypeEnum = PayOrderBusinessTypeEnum.getByCode(businessType);
		return isValidOrderType(payOrderBusinessTypeEnum);
	}

	/**
	 * 资产增加上链标识
	 *
	 * @param payOrder
	 */
	@Override
	public void saveUpChainFlag(TblPayOrder payOrder) {
		iInnerService.saveUpChainFlag(String.valueOf(payOrder.getAppUserId()), Longs.tryParse(payOrder.getBusinessRefId()));
	}

	/**
	 * 资产买卖订单确认
	 *
	 * @param payOrder        支付单
	 * @param callbackMessage 支付回调消息
	 * @param buyerUserId
	 */
	private boolean confirmAssetBuyOrder(TblPayOrder payOrder, PayCallbackMessage callbackMessage, String buyerUserId) {
		boolean needRefund = false;
		// 业务订单确认
		TransactionResponse transaction = iInnerService.queryPaySyncOne(buyerUserId, Longs.tryParse(payOrder.getBusinessRefId()));
		isNull(transaction, ErrorMessage.ORDER_OPERATE_FAILED, () -> log.error("支付中心支付成功，没有找到对应的业务订单 {}", JSONUtil.toJsonStr(callbackMessage)));
		if (Objects.equals(transaction.getDealState(), DealStateEnum.NOT_PAYED.code())) {
			ConfirmTransactionRequest confirmOrderRequest = ConfirmTransactionRequest
					.builder()
					.orderId(transaction.getOrderId())
					.from(Long.valueOf(transaction.getSellerUserId()))
					.to(Long.valueOf(transaction.getBuyerUserId()))
					.assetId(transaction.getAssetId())
					.actTotalPrice(payOrder.getPayMoney())
					.build();
			try {
				// 记录支付成功
				savePaySuccessRecord(payOrder, callbackMessage);
				iInnerService.confirmTransaction(confirmOrderRequest);
				// 资产增加上链标识
				if (Objects.equals(payOrder.getBusinessType(), PayOrderBusinessTypeEnum.PERSONAL_MINT.getCode())) {
					saveUpChainFlag(payOrder);
				}
				// 发送支付成功消息
				rocketMqService.sendPayOrderStatusChangeMsg(payOrder.getPayOrderId());
				return true;
			} catch (ChainException e) {
				log.error("支付中心支付成功，业务订单确认失败 {}", JSONUtil.toJsonStr(callbackMessage), e);
				// 处理失败，取消订单
				doPayCancel(payOrder, "支付中心支付成功，业务订单确认失败. exp:" + e.getMsg() + " callbackMessage:" + JSONUtil.toJsonStr(callbackMessage));
				needRefund = true;
			}
		} else if (Objects.equals(payOrder.getPayStatus(), PayOrderStatusEnum.PAY_CANCEL.getCode())) {
			if (alreadyApplyRefund(payOrder.getPayOrderId())) {
				log.warn("支付中心支付成功，业务订单已取消，已申请退款 {}", JSONUtil.toJsonStr(callbackMessage));
			} else {
				// 业务订单已取消，向支付中心申请退款
				needRefund = true;
			}
		} else {
			log.warn("支付处理失败，目标订单不是待支付状态！ {}", JSONUtil.toJsonStr(callbackMessage));
		}

		if (needRefund) {
			this.startRefundOrder(payOrder, callbackMessage);
		}
		return false;
	}

	@Override
	public void savePaySuccessRecord(TblPayOrder payOrder, PayCallbackMessage callbackMessage) {
		if (!iTblPayOrderService.updatePaySuccess(payOrder.getPayOrderId())) {
			throw new RuntimeException(ErrorMessage.ORDER_OPERATE_FAILED.getMessage());
		}
	}

	/**
	 * 订单退款
	 *
	 * @param orderRefundMessage 退款申请消息
	 */
	@Transactional(rollbackFor = Exception.class)
	@Override
	public void refundOrder(OrderRefundMessage orderRefundMessage) {
		log.warn("refundOrder 开始处理退款消息 orderRefundMessage:{}", orderRefundMessage);
	}

	/**
	 * 支付单状态确认
	 *
	 * @param confirmRequest
	 * @return
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public Boolean confirmPayStatus(@Valid ConfirmPayOrderRequest confirmRequest) {
		TblPayOrder payOrder = iTblPayOrderService.getPayOrder(confirmRequest.getPayOrderId(), confirmRequest.getAppUserId());
		if (payOrder == null) {
			log.error("confirmPayStatus failed. payOrder is null. confirmRequest:{}", confirmRequest);
			return false;
		}

		PayCenterOrderStatusResponse orderStatusResponse = refreshPayOrderStatus(payOrder.getPayOrderId(), String.valueOf(payOrder.getAppUserId()), payOrder
				.getPayMoney(), payOrder.getBusinessAttach());
		if (orderStatusResponse == null) {
			log.error("confirmPayStatus failed. orderStatusResponse is null. payOrder:{}", JSONUtil.toJsonStr(payOrder));
			return false;
		}
		if (Objects.equals(orderStatusResponse.getState(), 1)) {
			// 支付成功立即处理
			try {
				log.info("confirmPayStatus start handle pay success. payOrder:{}", JSONUtil.toJsonStr(payOrder));
				PayCallbackMessage payCallbackMessage = PayCallbackMessage
						.builder()
						.isRefund(0)
						.orderNo(String.valueOf(payOrder.getPayOrderId()))
						.userId(String.valueOf(payOrder.getAppUserId()))
						.build();
				payCallbackConsume(payCallbackMessage, true);
				return true;
			} catch (Exception e) {
				log.error("confirmPayStatus handle pay success failed. payOrder:{}", JSONUtil.toJsonStr(payOrder), e);
				return false;
			}
		} else if ((payOrder.getCreateTime() + cancelPayOrderGap * 60000) > System.currentTimeMillis()) {
			log.info("当前订单payOrder:{}未超过自动取消阈值时间：{}分钟", JSONUtil.toJsonStr(payOrder), cancelPayOrderGap);
			return true;
		} else {
			log.info("confirmPayStatus start handle pay timeout. payOrder:{}", JSONUtil.toJsonStr(payOrder));
			try {
				PayDelayMessage payDelayMessage = PayDelayMessage.builder().payOrderId(payOrder.getPayOrderId()).buyUserId(payOrder.getAppUserId()).build();
				payDelayCancel(payDelayMessage);
				return true;
			} catch (Exception e) {
				log.error("confirmPayStatus handle pay timeout failed. payOrder:{}", JSONUtil.toJsonStr(payOrder), e);
				return false;
			}
		}
	}

	/**
	 * 是否可以操作支付
	 *
	 * @return
	 */
	@Override
	public Boolean canOperatePay(String uid) {
		return canOperatePay || (canOperatePayUserIds != null && canOperatePayUserIds.contains(uid));
	}

	/**
	 * 取消订单（用户手动取消）
	 *
	 * @param uid     用户id
	 * @param request 取消参数
	 * @return 支付单状态变更响应
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public PayOrderStatusChangeResponse cancelOrder(String uid, @Valid PayOrderCancelRequest request) {
		TblPayOrder payOrder;
		if (StringUtils.isNumeric(request.getPayOrderId())) {
			payOrder = iTblPayOrderService.getPayOrder(Long.valueOf(request.getPayOrderId()), Long.valueOf(uid));
		} else if (request.getOrderType() != null && StringUtils.isNotBlank(request.getOrderId())) {
			payOrder = getCanOperatePayOrder(uid, request.getOrderType(), request.getOrderId());
		} else {
			throw new ChainException(ErrorMessage.ARGUMENT_NOT_VALID);
		}

		long payOrderId = payOrder.getPayOrderId();

		// 订单级别分布式锁同步
		String lockKey = String.format(RedisLockUtil.LOCK_KEY_PAY_ORDER, payOrderId);
		String lockValue = UUID.randomUUID().toString();
		boolean locked = false;
		try {
			locked = redisLockUtil.tryLock(lockKey, lockValue, 1, TimeUnit.MINUTES, 10, TimeUnit.SECONDS);
			if (!locked) {
				log.error("cancelOrder failed. 订单 {} 分布式锁同步失败", payOrderId);
				throw new ChainException(ErrorMessage.UNKNOWN_ERROR);
			}

			payOrder = iTblPayOrderService.getPayOrder(payOrderId, Long.valueOf(uid));
			isNull(payOrder, ErrorMessage.PAY_ORDER_NOT_EXISTS);
			isFalse(Objects.equals(payOrder.getPayStatus(), PayOrderStatusEnum.UN_PAY.getCode()), ErrorMessage.PAY_ORDER_STATUS_EX);

			if (payOrder.getBusinessOrderId() != null && payOrder.getBusinessOrderId() > 0L) {
				cancelBusinessOrder(payOrder.getBusinessOrderId(), "用户手动取消");
				return PayOrderStatusChangeResponse
						.builder()
						.payOrderId(String.valueOf(payOrder.getPayOrderId()))
						.payStatus(PayOrderStatusEnum.PAY_CANCEL.getCode())
						.build();
			}

			// 检查支付中心订单状态
			PayCenterOrderStatusResponse orderStatusResponse = refreshPayOrderStatus(payOrder.getPayOrderId(), String.valueOf(payOrder.getAppUserId()), payOrder
					.getPayMoney(), payOrder.getBusinessAttach());
			// 接口调用失败处理
			isNull(orderStatusResponse, ErrorMessage.UNKNOWN_ERROR);
			if (Objects.equals(orderStatusResponse.getState(), PAY_CENTER_ORDER_STATE_NOT_PAY)) {
				log.info("cancelOrder start. payOrder:{} orderStatusResponse:{}", JSONUtil.toJsonStr(payOrder), orderStatusResponse);
				PayOrderBusinessTypeEnum orderTypeEnum = PayOrderBusinessTypeEnum.getByCode(payOrder.getBusinessType());
				payOrderOperatorFactory.getOperator(orderTypeEnum).doPayCancel(payOrder, "用户手动取消");
				payOrder = iTblPayOrderService.getPayOrder(Long.valueOf(payOrderId), Long.valueOf(uid));
				return PayOrderStatusChangeResponse.builder().payOrderId(String.valueOf(payOrder.getPayOrderId())).payStatus(payOrder.getPayStatus()).build();
			} else {
				log
						.error("cancelOrder failed. already paid. payOrder:{} orderStatusResponse:{}", JSONUtil.toJsonStr(payOrder), JSONUtil
								.toJsonStr(orderStatusResponse));
				throw new ChainException(ErrorMessage.PAY_ORDER_STATUS_EX);
			}
		} finally {
			if (locked) {
				redisLockUtil.releaseLock(lockKey, lockValue);
			}
		}
	}

	private TblPayOrder getCanOperatePayOrder(String uid, @NotNull(message = "业务订单类型不能为空") Integer orderType, @NotNull(message = "业务订单id不能为空") String orderId) {
		OrderTypeEnum orderTypeEnum = OrderTypeEnum.queryConvert(orderType);
		isNull(orderTypeEnum, ErrorMessage.ORDER_OPERATE_FAILED, () -> log.error("invalid order type. orderType:{} orderId:{}", orderType, orderId));
		PayOrderBusinessTypeEnum businessTypeEnum;
		if (Objects.equals(orderType, OrderTypeEnum.NORMAL.code())) {
			businessTypeEnum = PayOrderBusinessTypeEnum.NORMAL;
		} else if (Objects.equals(orderType, OrderTypeEnum.PERSONAL_MINT.code())) {
			businessTypeEnum = PayOrderBusinessTypeEnum.PERSONAL_MINT;
		} else {
			log.error("invalid order type. orderType:{} orderId:{}", orderType, orderId);
			throw new ChainException(ErrorMessage.ORDER_OPERATE_FAILED);
		}

		TblPayOrder payOrder = iTblPayOrderService.getByBusiness(businessTypeEnum, orderId);
		isFalse(payOrder != null && Objects.equals(payOrder.getAppUserId(), Long.valueOf(uid)), ErrorMessage.PAY_ORDER_NOT_EXISTS);
		return payOrder;
	}

	/**
	 * 未支付继续支付
	 *
	 * @param uid
	 * @param continueRequest
	 * @return
	 */
	@Override
	public PayCenterArgsResponse continuePay(String uid, PayContinueRequest continueRequest) {
		TblPayOrder payOrder;
		if (StringUtils.isNumeric(continueRequest.getPayOrderId())) {
			payOrder = iTblPayOrderService.getPayOrder(Long.valueOf(continueRequest.getPayOrderId()), Long.valueOf(uid));
		} else if (continueRequest.getOrderType() != null && StringUtils.isNotBlank(continueRequest.getOrderId())) {
			payOrder = getCanOperatePayOrder(uid, continueRequest.getOrderType(), continueRequest.getOrderId());
		} else {
			throw new ChainException(ErrorMessage.ARGUMENT_NOT_VALID);
		}

		long payOrderId = payOrder.getPayOrderId();
		// 订单级别分布式锁同步
		String lockKey = String.format(RedisLockUtil.LOCK_KEY_PAY_ORDER, payOrderId);
		String lockValue = UUID.randomUUID().toString();
		boolean locked = false;
		try {
			locked = redisLockUtil.tryLock(lockKey, lockValue, 1, TimeUnit.MINUTES, 10, TimeUnit.SECONDS);
			if (!locked) {
				log.error("cancelOrder failed. 订单 {} 分布式锁同步失败", payOrderId);
				throw new ChainException(ErrorMessage.UNKNOWN_ERROR);
			}

			payOrder = iTblPayOrderService.getPayOrder(payOrderId, Long.valueOf(uid));
			isNull(payOrder, ErrorMessage.PAY_ORDER_NOT_EXISTS);
			isFalse(Objects.equals(payOrder.getPayStatus(), PayOrderStatusEnum.UN_PAY.getCode()), ErrorMessage.PAY_ORDER_STATUS_EX);

			// 检查支付中心订单状态
			PayCenterOrderStatusResponse orderStatusResponse = refreshPayOrderStatus(payOrder.getPayOrderId(), String.valueOf(payOrder.getAppUserId()), payOrder
					.getPayMoney(), payOrder.getBusinessAttach());
			isNull(orderStatusResponse, ErrorMessage.CHECK_PAY_ORDER_STATUS_EX);
			if (!Objects.equals(orderStatusResponse.getState(), PAY_CENTER_ORDER_STATE_NOT_PAY)) {
				log
						.error("continuePay failed. already paid. payOrder:{} orderStatusResponse:{}", JSONUtil.toJsonStr(payOrder), JSONUtil
								.toJsonStr(orderStatusResponse));
				throw new ChainException(ErrorMessage.PAY_ORDER_STATUS_EX);
			}

			AssetInfoResponse asset = null;
			PayOrderBusinessTypeEnum businessTypeEnum = PayOrderBusinessTypeEnum.getByCode(payOrder.getBusinessType());
			if (Objects.equals(businessTypeEnum, PayOrderBusinessTypeEnum.NORMAL) || Objects.equals(businessTypeEnum, PayOrderBusinessTypeEnum.PERSONAL_MINT)) {
				TransactionResponse assetTransaction = iInnerService.queryPaySyncOne(uid, Longs.tryParse(payOrder.getBusinessRefId()));
				isNull(assetTransaction, ErrorMessage.TRANSATION_NOT_EXIST);
				isFalse(Objects.equals(assetTransaction.getDealState(), DealStateEnum.NOT_PAYED.code()), ErrorMessage.TRANSATION_STATE_EX);
				asset = iInnerService.infoWithAssetId(assetTransaction.getAssetId());
			}
			UserInfoResponse userInfo = iInnerService.userInfo(Long.valueOf(uid));
			return payCenterHttpService.buildCreateOrderParams(payOrder, userInfo, continueRequest.getBackUrl(), asset);
		} finally {
			if (locked) {
				redisLockUtil.releaseLock(lockKey, lockValue);
			}
		}
	}

	/**
	 * 获取支付订单状态
	 *
	 * @param request
	 * @return
	 */
	@Override
	public Integer getPayStatus(@NotNull GetPayStatusRequest request) {
		TblPayOrder payOrder = null;
		if (request.getPayOrderId() != null && request.getPayOrderId() > 0) {
			payOrder = iTblPayOrderService.getById(request.getPayOrderId());
		} else if (request.getTransactionId() != null && request.getTransactionId() > 0 && request.getOrderType() != null) {
			OrderTypeEnum orderTypeEnum = OrderTypeEnum.queryConvert(request.getOrderType());
			if (Objects.equals(orderTypeEnum, OrderTypeEnum.PERSONAL_MINT)) {
				payOrder = iTblPayOrderService.getByBusiness(PayOrderBusinessTypeEnum.PERSONAL_MINT, String.valueOf(request.getTransactionId()));
			} else if (Objects.equals(orderTypeEnum, OrderTypeEnum.NORMAL)) {
				payOrder = iTblPayOrderService.getByBusiness(PayOrderBusinessTypeEnum.NORMAL, String.valueOf(request.getTransactionId()));
			}
		}
		if (payOrder == null) {
			return null;
		}

		PayOrderStatusEnum payOrderStatusEnum = PayOrderStatusEnum.getByCode(payOrder.getPayStatus());
		if (Objects.equals(payOrderStatusEnum, PayOrderStatusEnum.UN_PAY)) {
			PayCenterOrderStatusResponse payCenterOrderStatusResponse = refreshPayOrderStatus(payOrder.getPayOrderId(), String
					.valueOf(payOrder.getAppUserId()), payOrder.getPayMoney(), payOrder.getBusinessAttach());
			if (payCenterOrderStatusResponse != null
					&& (Objects.equals(payCenterOrderStatusResponse.getState(), 3) || Objects.equals(payCenterOrderStatusResponse.getState(), 1))) {
				payOrderStatusEnum = PayOrderStatusEnum.PAYING;
			}
		}
		return payOrderStatusEnum.getCode();
	}

	/**
	 * 批量获取支付订单状态
	 *
	 * @param request
	 * @return
	 */
	@Override
	public Map<Long, Integer> getPayStatusMap(@Valid GetPayStatusMapRequest request) {
		Set<Long> transactionIds = request.getTransactionIds();
		if (CollectionUtils.isEmpty(transactionIds)) {
			return new HashMap<>();
		} else if (transactionIds.size() > 50) {
			throw new ChainException(ErrorMessage.ARGUMENT_NOT_VALID);
		}
		int businessType = 0;
		if (Objects.equals(OrderTypeEnum.PERSONAL_MINT.code(), request.getOrderType())) {
			businessType = PayOrderBusinessTypeEnum.PERSONAL_MINT.getCode();
		} else if (Objects.equals(OrderTypeEnum.NORMAL.code(), request.getOrderType())) {
			businessType = PayOrderBusinessTypeEnum.NORMAL.getCode();
		} else {
			throw new ChainException(ErrorMessage.ARGUMENT_NOT_VALID);
		}

		QueryWrapper<TblPayOrder> queryWrapper = new QueryWrapper<>();
		queryWrapper.eq("business_type", businessType);
		queryWrapper.in("business_ref_id", transactionIds);
		List<TblPayOrder> payOrders = iTblPayOrderService.list(queryWrapper);
		List<CompletableFuture<Pair<Long, PayOrderStatusEnum>>> queryPayStatusFutures = new ArrayList<>();
		Map<Long, PayOrderStatusEnum> payOrderStatusMap = new HashMap<>();
		for (TblPayOrder payOrder : payOrders) {
			PayOrderStatusEnum payOrderStatusEnum = PayOrderStatusEnum.getByCode(payOrder.getBusinessType());
			if (Objects.equals(payOrderStatusEnum, PayOrderStatusEnum.UN_PAY)) {
				CompletableFuture<Pair<Long, PayOrderStatusEnum>> task = CompletableFuture.supplyAsync(() -> {
					PayCenterOrderStatusResponse payCenterOrderStatusResponse = refreshPayOrderStatus(payOrder.getPayOrderId(), String
							.valueOf(payOrder.getAppUserId()), payOrder.getPayMoney(), payOrder.getBusinessAttach());
					if (payCenterOrderStatusResponse != null && Objects.equals(payCenterOrderStatusResponse.getState(), 3)) {
						return Pair.of(payOrder.getPayOrderId(), PayOrderStatusEnum.PAYING);
					} else {
						return null;
					}
				}, EXECUTOR);
				queryPayStatusFutures.add(task);
			}
		}

		if (!CollectionUtils.isEmpty(queryPayStatusFutures)) {
			queryPayStatusFutures.forEach(future -> {
				try {
					Pair<Long, PayOrderStatusEnum> pair = future.get(3, TimeUnit.SECONDS);
					if (pair != null && pair.getRight() != null) {
						payOrderStatusMap.put(pair.getLeft(), pair.getRight());
					}
				} catch (InterruptedException e) {
					Thread.currentThread().interrupt();
				} catch (Exception e) {
					log.error("queryPayOrderStatus failed. ", e);
				}
			});
		}

		Map<Long, Integer> result = new HashMap<>(transactionIds.size());
		payOrders.forEach(payOrder -> {
			long payOrderId = payOrder.getPayOrderId();
			if (payOrderStatusMap.containsKey(payOrderId)) {
				result.put(payOrderId, payOrderStatusMap.get(payOrderId).getCode());
			} else {
				result.put(payOrderId, payOrder.getPayStatus());
			}
		});
		return result;
	}

	/**
	 * 是否需要实名认证
	 *
	 * @param user
	 * @return
	 */
	private boolean checkAuth(UserInfoResponse user) {
		if (!checkAuthSwitch) {
			return false;
		}
		if (Objects.isNull(user)) {
			throw new ChainException(ErrorMessage.USER_NOT_EXIST);
		}
		Long queryAuthBefore = Optional.ofNullable(user).map(UserInfoResponse::getAuthBefore).orElse(0L);
		if (queryAuthBefore.longValue() == 0) {
			return true;
		}
		long minutesDifference = TimeUnit.MILLISECONDS.toMinutes((System.currentTimeMillis() - queryAuthBefore));
		return minutesDifference > authCheckFrequency;
	}

	/**
	 * 判断是否已申请退款
	 *
	 * @param payOrderId
	 * @return
	 */
	@Override
	public boolean alreadyApplyRefund(Long payOrderId) {
		long refundRecordCount = tblPayOrderRefundRecordService.countByPayOrderId(payOrderId);
		return refundRecordCount > 0;
	}

	/**
	 * 发起退款
	 *
	 * @param payOrder
	 */
	@Override
	public void startRefundOrder(TblPayOrder payOrder, PayCallbackMessage callbackMessage) {
		log.error("发起退款 payOrder:{}", JSONUtil.toJsonStr(payOrder));
		// 插入待退款记录
		long now = System.currentTimeMillis();
		TblPayOrderRefundRecord refundRecord = TblPayOrderRefundRecord
				.builder()
				.payOrderId(payOrder.getPayOrderId())
				.refundId(IdUtil.getSnowflakeNextId())
				.refundMoney(payOrder.getPayMoney())
				.refundStatus(PayOrderRefundStatusEnum.NEED_REFUND.getCode())
				.createTime(now)
				.updateTime(now)
				.build();
		tblPayOrderRefundRecordService.save(refundRecord);
	}

	/**
	 * 修复部分历史订单支付中心数据
	 *
	 * @return
	 */
	@Override
	public Boolean fixPayCenterData() {
		LambdaQueryChainWrapper<TblPayOrder> query = new LambdaQueryChainWrapper<>(iTblPayOrderService.getBaseMapper());
		List<TblPayOrder> result = query
				.eq(TblPayOrder::getPayStatus, PayOrderStatusEnum.PAY_SUCCESS.getCode())
				.gt(TblPayOrder::getPayMoney, BigDecimal.ZERO)
				.and(i -> i.isNull(TblPayOrder::getPayTradeNo).or().apply("pay_order_id = pay_trade_no"))
				.orderByAsc(TblPayOrder::getPayOrderId)
				.last("limit 10")
				.list();
		if (CollectionUtils.isEmpty(result)) {
			return true;
		}
		log.info("fixPayCenterData start, total:{}", result.size());
		while (!CollectionUtils.isEmpty(result)) {
			handleFixPayCenterData(result);
			query.gt(TblPayOrder::getPayOrderId, result.get(result.size() - 1).getPayOrderId());
			result = query.list();
		}
		return true;
	}

	/**
	 * 测试用户重置价格
	 *
	 * @param appUserId
	 * @param realUnitPrice
	 * @return
	 */
	@Override
	public BigDecimal testUserResetPrice(Long appUserId, BigDecimal realUnitPrice) {
		if (!CollectionUtils.isEmpty(resetPriceTestUserIds) && resetPriceTestUserIds.contains(String.valueOf(appUserId))) {
			return new BigDecimal("0.01");
		}
		return realUnitPrice;
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public PayCenterArgsResponseV3 createPayOrderV3(String uid, CreateOrderRequest makeOrder) {
		GoodsInfo goodsInfo = new GoodsInfo();
		PayCenterArgsResponse responseV2 = createPayOrder(uid, makeOrder, goodsInfo);
		if (responseV2.isAutoSuccessOrder()) {
			PayCenterArgsResponseV3 responseV3 = new PayCenterArgsResponseV3();
			BeanUtils.copyProperties(responseV2, responseV3, "payParam", "payCenterVersion");
			return responseV3;
		}
		try {
			PayCenterArgsResponseV3 responseV3 = payCenterV3HttpService.convertFromV2(responseV2, goodsInfo);

			// 存储预下单相关参数
			long payOrderId = Long.valueOf(responseV2.getPayParam().getOrderNo().substring(4));
			TblPayOrder payOrder = iTblPayOrderService.getById(payOrderId);
			PayAttach payAttach;
			if (StringUtils.isBlank(payOrder.getBusinessAttach())) {
				payAttach = new PayAttach();
				payAttach.setPayCenterVersion("v3");
				payAttach.setPrepayId(responseV3.getPayParam().getPrepayId());
			} else {
				payAttach = JSONUtil.toBean(payOrder.getBusinessAttach(), PayAttach.class);
				payAttach.setPayCenterVersion("v3");
				payAttach.setPrepayId(responseV3.getPayParam().getPrepayId());
			}
			iTblPayOrderService.updatePayOrderBusinessAttach(payOrderId, JSONUtil.toJsonStr(payAttach));

			if (skipRealPay()) {
				log.warn("skip real pay in test mode. payOrderId:{}", payOrderId);
				PayCallbackMessage payCallbackMessage = PayCallbackMessage
						.builder()
						.isRefund(0)
						.orderNo(String.valueOf(payOrder.getPayOrderId()))
						.userId(String.valueOf(payOrder.getAppUserId()))
						.build();
				payCallbackConsume(payCallbackMessage, true);
				responseV3.setAutoSuccessOrder(true);
				responseV3.setPayParam(null);
			}

			return responseV3;
		} catch (Exception e) {
			log.error("convertFromV2 failed. responseV2:" + JSONUtil.toJsonStr(responseV2), e);
			throw new ChainException(ErrorMessage.ORDER_CREATE_FAILED);
		}
	}

	/**
	 * 支付回调
	 *
	 * @param request
	 */
	@Override
	public void payNotify(PayNotifyRequest request) {
		if (payCenterV3HttpService.checkNotifySign(request)) {
			if (Objects.equals("0", request.getStatus())) {
				String orderNo = request.getOrderNo().substring(4);
				PayCallbackMessage payCallbackMessage = PayCallbackMessage.builder().isRefund(0).orderNo(orderNo).userId(request.getOpenId()).build();
				payCallbackConsume(payCallbackMessage, true);
			} else {
				log.warn("支付失败 request:{}", JSONUtil.toJsonStr(request));
			}
		} else {
			log.error("验签失败 request:{}", JSONUtil.toJsonStr(request));
			throw new ChainException(ErrorMessage.UNKNOWN_ERROR);
		}
	}

	@Override
	public PayCenterArgsResponseV3 continuePayV3(String uid, PayContinueRequest continueRequest, TblPayOrder payOrder) {
		PayCenterArgsResponse responseV2 = continuePay(uid, continueRequest);
		PayOrderBusinessTypeEnum orderTypeEnum = PayOrderBusinessTypeEnum.getByCode(payOrder.getBusinessType());
		IPayOrderOperator orderOperator = payOrderOperatorFactory.getOperator(orderTypeEnum);
		if (orderOperator == null) {
			throw new ChainException(ErrorMessage.UN_SUPPORTED_ORDER_TYPE);
		}
		GoodsInfo goodsInfo = orderOperator.getGoodsInfo(payOrder);
		try {
			PayCenterArgsResponseV3 responseV3 = payCenterV3HttpService.convertFromV2(responseV2, goodsInfo);

			// 存储预下单相关参数
			long payOrderId = payOrder.getPayOrderId();
			PayAttach payAttach;
			if (StringUtils.isBlank(payOrder.getBusinessAttach())) {
				payAttach = new PayAttach();
				payAttach.setPayCenterVersion("v3");
				payAttach.setPrepayId(responseV3.getPayParam().getPrepayId());
			} else {
				payAttach = JSONUtil.toBean(payOrder.getBusinessAttach(), PayAttach.class);
				payAttach.setPayCenterVersion("v3");
				payAttach.setPrepayId(responseV3.getPayParam().getPrepayId());
			}
			iTblPayOrderService.updatePayOrderBusinessAttach(payOrderId, JSONUtil.toJsonStr(payAttach));
			return responseV3;
		} catch (Exception e) {
			log.error("convertFromV2 failed. responseV2:" + JSONUtil.toJsonStr(responseV2), e);
			throw new ChainException(ErrorMessage.ORDER_OPERATE_FAILED);
		}
	}

	/**
	 * 生成订单
	 *
	 * @param uid              通通用户id
	 * @param makeOrderRequest
	 * @return
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public TblBusinessOrder makeBusinessOrder(String uid, @NotNull MakeOrderRequest makeOrderRequest) {
		UserInfoResponse user = iInnerService.userInfo(Long.valueOf(uid));
		isFalse(user != null && Objects.equals(user.getStatus(), 0), ErrorMessage.USER_STATUS_EX);
		isFalse(user.getAuthBefore() != null, ErrorMessage.NEED_AUTHENTICATION);
		// 检查支付功能是否可用
		if (!canOperatePay(uid)) {
			throw new ChainException(ErrorMessage.PAY_FUNCTION_NOT_ENABLE);
		}

		PayOrderBusinessTypeEnum businessTypeEnum = PayOrderBusinessTypeEnum.valueOf(makeOrderRequest.getOrderType());
		BusinessOrderOperator businessOrderOperator = businessOrderOperatorFactory.getOperator(businessTypeEnum);
		isNull(businessOrderOperator, ErrorMessage.UN_SUPPORTED_ORDER_TYPE);
		return businessOrderOperator.makeOrder(uid, makeOrderRequest);
	}

	/**
	 * 生产支付参数
	 *
	 * @param uid
	 * @param businessOrder
	 * @param backUrl
	 * @return
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public PayCenterArgsResponseV3 generatePayParam(String uid, TblBusinessOrder businessOrder, String backUrl) {
		// 检查支付功能是否可用
		if (!canOperatePay(uid)) {
			throw new ChainException(ErrorMessage.PAY_FUNCTION_NOT_ENABLE);
		}

		TblPayOrder payOrder = iTblPayOrderService.getPayOrderByBusinessOrder(businessOrder.getOrderId());
		if (payOrder == null) {
			payOrder = createPayOrder4BusinessOrder(uid, businessOrder);
		}
		isFalse(Objects.equals(payOrder.getPayStatus(), PayOrderStatusEnum.UN_PAY.getCode()), ErrorMessage.PAY_ORDER_STATUS_EX);

		// 预下单
		boolean skipRealPay = skipRealPay();
		if (skipRealPay || businessOrder.getTotalPrice().compareTo(BigDecimal.ZERO) == 0) {
			if (skipRealPay) {
				log.warn("skip real pay in test mode. businessOrder:{}", JSONUtil.toJsonStr(businessOrder));
			} else {
				log.warn("skip real pay for zero money order. businessOrder:{}", JSONUtil.toJsonStr(businessOrder));
			}
			PayCallbackMessage payCallbackMessage = PayCallbackMessage
					.builder()
					.isRefund(0)
					.orderNo(String.valueOf(payOrder.getPayOrderId()))
					.userId(String.valueOf(payOrder.getAppUserId()))
					.build();
			// 资产交易记录确认
			this.paySuccess(payCallbackMessage, false);
			return PayCenterArgsResponseV3.builder().autoSuccessOrder(true).build();
		}
		if (StringUtils.isBlank(backUrl)) {
			backUrl = payBackUrl;
		}
		try {
			PayCenterArgsResponseV3 payCenterArgsResponseV3 = payCenterV3HttpService.prePay(businessOrder, payOrder, backUrl);
			injectPrepayId(payOrder, payCenterArgsResponseV3.getPayParam().getPrepayId());
			return payCenterArgsResponseV3;
		} catch (Exception e) {
			log.error("prePay failed. businessOrder:{} payOrder:{}", JSONUtil.toJsonStr(businessOrder), JSONUtil.toJsonStr(payOrder), e);
			throw new ChainException(ErrorMessage.ORDER_OPERATE_FAILED);
		}
	}

	@Transactional(rollbackFor = Exception.class)
	@Override
	public PayCenterArgsResponseV3 generatePayParam(String uid, TblPayOrder payOrder, String backUrl) {
		isNull(payOrder, ErrorMessage.PAY_ORDER_NOT_EXISTS);
		isFalse(Objects.equals(payOrder.getPayStatus(), PayOrderStatusEnum.UN_PAY.getCode()), ErrorMessage.PAY_ORDER_STATUS_EX);

		// 预下单
		boolean skipRealPay = skipRealPay();
		if (skipRealPay || payOrder.getOrderMoney().compareTo(BigDecimal.ZERO) == 0) {
			if (skipRealPay) {
				log.warn("skip real pay in test mode. payOrder:{}", JSONUtil.toJsonStr(payOrder));
			} else {
				log.warn("skip real pay for zero money order. payOrder:{}", JSONUtil.toJsonStr(payOrder));
			}
			PayCallbackMessage payCallbackMessage = PayCallbackMessage
					.builder()
					.isRefund(0)
					.orderNo(String.valueOf(payOrder.getPayOrderId()))
					.userId(String.valueOf(payOrder.getAppUserId()))
					.build();
			// 资产交易记录确认
			this.paySuccess(payCallbackMessage, false);
			return PayCenterArgsResponseV3.builder().autoSuccessOrder(true).build();
		}
		if (StringUtils.isBlank(backUrl)) {
			backUrl = payBackUrl;
		}
		TblBusinessOrder businessOrder = iTblBusinessOrderService.getById(payOrder.getBusinessOrderId());
		isNull(businessOrder, ErrorMessage.BUSINESS_ORDER_NOT_EXISTS);
		try {
			PayCenterArgsResponseV3 payCenterArgsResponseV3 = payCenterV3HttpService.prePay(businessOrder, payOrder, backUrl);
			injectPrepayId(payOrder, payCenterArgsResponseV3.getPayParam().getPrepayId());
			return payCenterArgsResponseV3;
		} catch (Exception e) {
			log.error("prePay failed. businessOrder:{} payOrder:{}", JSONUtil.toJsonStr(businessOrder), JSONUtil.toJsonStr(payOrder), e);
			throw new ChainException(ErrorMessage.ORDER_OPERATE_FAILED);
		}
	}

	private void injectPrepayId(TblPayOrder payOrder, String prepayId) {
		String attach = payOrder.getBusinessAttach();
		PayAttach payAttach;
		if (StringUtils.isBlank(attach)) {
			payAttach = new PayAttach();
		} else {
			payAttach = JSONUtil.toBean(attach, PayAttach.class);
		}
		payAttach.setPayCenterVersion("v3");
		payAttach.setPrepayId(prepayId);
		iTblPayOrderService.updatePayOrderBusinessAttach(payOrder.getPayOrderId(), JSONUtil.toJsonStr(payAttach));
	}

	/**
	 * 订单支付成功处理
	 *
	 * @param payCallbackMessage
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public void paySuccess(PayCallbackMessage payCallbackMessage, boolean needReCheck) {
		long payOrderId = Long.parseLong(payCallbackMessage.getOrderNo());
		// step1.检查订单状态并加锁
		TblPayOrder payOrder = iTblPayOrderService.getByIdForUpdate(payOrderId);
		isNull(payOrder, ErrorMessage.PAY_ORDER_NOT_EXISTS);
		PayOrderStatusEnum payOrderStatusEnum = PayOrderStatusEnum.getByCode(payOrder.getPayStatus());
		isFalse(payOrderStatusEnum.canUpdateTo(PayOrderStatusEnum.PAY_SUCCESS), ErrorMessage.PAY_ORDER_STATUS_EX);
		TblBusinessOrder businessOrder = iTblBusinessOrderService.getByIdForUpdate(payOrder.getBusinessOrderId());
		isNull(businessOrder, ErrorMessage.BUSINESS_ORDER_NOT_EXISTS);
		payOrderStatusEnum = PayOrderStatusEnum.getByCode(businessOrder.getOrderStatus());
		isFalse(payOrderStatusEnum.canUpdateTo(PayOrderStatusEnum.PAY_SUCCESS), ErrorMessage.BUSINESS_ORDER_STATUS_EX);

		// step2.二次确认支付状态
		if (needReCheck) {
			PayCenterOrderStatusResponse orderStatusResponse = refreshPayOrderStatus(payOrder.getPayOrderId(), String.valueOf(payOrder.getAppUserId()), payOrder
					.getOrderMoney(), payOrder.getBusinessAttach());
			if (orderStatusResponse == null) {
				throw new RuntimeException("获取订单支付状态失败：payOrderId:" + payOrderId);
			} else if (!Objects.equals(orderStatusResponse.getState(), 1)) {
				log.error("收到支付成功MQ但订单查询接口未返回支付成功。payOrderId:{},orderStatusResponse:{}", payOrderId, JSONUtil.toJsonStr(payCallbackMessage));
				if (!skipRealPay()) {
					return;
				}
			}
		}

		// step3.更新支付单和订单状态
		if (StringUtils.isNotBlank(payCallbackMessage.getThirdTradeNo())) {
			isFalse(iTblPayOrderService
					.updatePaySuccess(payOrder.getPayOrderId(), payCallbackMessage.getThirdTradeNo(), payCallbackMessage.getPayMode(), payCallbackMessage
							.getPayModeSub()), ErrorMessage.ORDER_OPERATE_FAILED);
		} else {
			isFalse(iTblPayOrderService.updatePaySuccess(payOrder.getPayOrderId()), ErrorMessage.ORDER_OPERATE_FAILED);
		}
		isFalse(iTblBusinessOrderService.updateOrderPaySuccess(businessOrder), ErrorMessage.ORDER_OPERATE_FAILED);

		// step3.支付成功后业务处理（通过mq方式异步驱动）
		PayOrderBusinessTypeEnum businessTypeEnum = PayOrderBusinessTypeEnum.getByCode(payOrder.getBusinessType());
		rocketMqService.sendBusinessOrderStatusChangeMsg(businessOrder.getOrderId(), businessTypeEnum, PayOrderStatusEnum.PAY_SUCCESS);
	}

	@Override
	public void cancelBusinessOrder(@Positive Long businessOrderId, String reasonRemark) {
		// step1.检查订单状态并加锁
		TblPayOrder payOrder = iTblPayOrderService.getByBusinessOrderIdForUpdate(businessOrderId);
		isNull(payOrder, ErrorMessage.PAY_ORDER_NOT_EXISTS);
		PayOrderStatusEnum payOrderStatusEnum = PayOrderStatusEnum.getByCode(payOrder.getPayStatus());
		isFalse(payOrderStatusEnum.canUpdateTo(PayOrderStatusEnum.PAY_CANCEL), ErrorMessage.PAY_ORDER_STATUS_EX);
		TblBusinessOrder businessOrder = iTblBusinessOrderService.getByIdForUpdate(businessOrderId);
		isNull(businessOrder, ErrorMessage.BUSINESS_ORDER_NOT_EXISTS);
		payOrderStatusEnum = PayOrderStatusEnum.getByCode(businessOrder.getOrderStatus());
		isFalse(payOrderStatusEnum.canUpdateTo(PayOrderStatusEnum.PAY_SUCCESS), ErrorMessage.BUSINESS_ORDER_STATUS_EX);

		// step2.更新支付单和订单状态
		isFalse(iTblPayOrderService.updatePayCancel(payOrder.getPayOrderId(), reasonRemark), ErrorMessage.ORDER_OPERATE_FAILED);
		isFalse(iTblBusinessOrderService.updateOrderCancel(businessOrder), ErrorMessage.ORDER_OPERATE_FAILED);

		// step3.支付成功后业务处理（通过mq方式异步驱动）
		PayOrderBusinessTypeEnum businessTypeEnum = PayOrderBusinessTypeEnum.getByCode(payOrder.getBusinessType());
		rocketMqService.sendBusinessOrderStatusChangeMsg(businessOrder.getOrderId(), businessTypeEnum, PayOrderStatusEnum.PAY_CANCEL);
	}

	/**
	 * 支付结果回调处理
	 *
	 * @param request
	 */
	@Override
	public void payNotifyV2(PayNotifyRequest request) {
		if (payCenterV3HttpService.checkNotifySign(request)) {
			if (Objects.equals("0", request.getStatus())) {
				String orderNo = request.getOrderNo().substring(4);
				PayCallbackMessage payCallbackMessage = PayCallbackMessage
						.builder()
						.isRefund(0)
						.orderNo(orderNo)
						.userId(request.getOpenId())
						.thirdTradeNo(request.getThirdTradeNo())
						.payMode(request.getPayMode())
						.payModeSub(request.getPayModeSub())
						.build();
				paySuccess(payCallbackMessage, true);
			} else {
				log.warn("支付失败 request:{}", JSONUtil.toJsonStr(request));
			}
		} else {
			log.error("验签失败 request:{}", JSONUtil.toJsonStr(request));
			throw new ChainException(ErrorMessage.UNKNOWN_ERROR);
		}
	}

	@Override
	public Boolean confirmPayStatusV2(ConfirmPayOrderRequest confirmRequest) {
		TblPayOrder payOrder = iTblPayOrderService.getPayOrder(confirmRequest.getPayOrderId(), confirmRequest.getAppUserId());
		if (payOrder == null) {
			log.error("confirmPayStatusV2 failed. payOrder is null. confirmRequest:{}", confirmRequest);
			return false;
		}
		if (payOrder.getBusinessOrderId() == null) {
			return confirmPayStatus(confirmRequest);
		}

		PayCenterOrderStatusResponse orderStatusResponse = refreshPayOrderStatus(payOrder.getPayOrderId(), String.valueOf(payOrder.getAppUserId()), payOrder
				.getPayMoney(), payOrder.getBusinessAttach());
		if (orderStatusResponse == null) {
			log.error("confirmPayStatusV2 failed. orderStatusResponse is null. payOrder:{}", JSONUtil.toJsonStr(payOrder));
			return false;
		}
		if (Objects.equals(orderStatusResponse.getState(), 1)) {
			// 支付成功立即处理
			try {
				log.info("confirmPayStatusV2 start handle pay success. payOrder:{}", JSONUtil.toJsonStr(payOrder));
				PayCallbackMessage payCallbackMessage = PayCallbackMessage
						.builder()
						.isRefund(0)
						.orderNo(String.valueOf(payOrder.getPayOrderId()))
						.userId(String.valueOf(payOrder.getAppUserId()))
						.build();
				paySuccess(payCallbackMessage, false);
				return true;
			} catch (Exception e) {
				log.error("confirmPayStatusV2 handle pay success failed. payOrder:{}", JSONUtil.toJsonStr(payOrder), e);
				return false;
			}
		} else if ((payOrder.getCreateTime() + cancelPayOrderGap * 60000) > System.currentTimeMillis()) {
			log.info("当前订单payOrder:{}未超过自动取消阈值时间：{}分钟", JSONUtil.toJsonStr(payOrder), cancelPayOrderGap);
			return true;
		} else {
			log.info("confirmPayStatusV2 start handle pay timeout. payOrder:{}", JSONUtil.toJsonStr(payOrder));
			try {
				cancelBusinessOrder(payOrder.getBusinessOrderId(), "支付超时");
				return true;
			} catch (Exception e) {
				log.error("confirmPayStatusV2 handle pay timeout failed. payOrder:{}", JSONUtil.toJsonStr(payOrder), e);
				return false;
			}
		}

	}

	private TblPayOrder createPayOrder4BusinessOrder(String uid, TblBusinessOrder businessOrder) {
		long now = System.currentTimeMillis();
		PayOrderBusinessTypeEnum businessTypeEnum = PayOrderBusinessTypeEnum.valueOf(GoodsTypeEnum.getByCode(businessOrder.getGoodsType()).name());
		TblPayOrder payOrder = new TblPayOrder();
		payOrder.setPayOrderId(IdUtil.getSnowflakeNextId());
		payOrder.setAppUserId(Long.valueOf(uid));
		payOrder.setBusinessType(businessTypeEnum.getCode());
		payOrder.setBusinessOrderId(businessOrder.getOrderId());
		payOrder.setPayStatus(PayOrderStatusEnum.UN_PAY.getCode());
		payOrder.setOrderMoney(businessOrder.getTotalPrice());
		payOrder.setPayMoney(businessOrder.getTotalPrice());
		payOrder.setBusinessRefId(businessOrder.getBusinessRefId());
		payOrder.setCreateTime(now);
		payOrder.setUpdateTime(now);
		payOrder.setBusinessAttach(JSONUtil.toJsonStr(generatePayAttach(businessOrder)));
		isFalse(iTblPayOrderService.save(payOrder), ErrorMessage.ORDER_OPERATE_FAILED);
		return payOrder;
	}

	private PayAttach generatePayAttach(TblBusinessOrder businessOrder) {
		PayOrderBusinessTypeEnum businessTypeEnum = PayOrderBusinessTypeEnum.valueOf(GoodsTypeEnum.getByCode(businessOrder.getGoodsType()).name());
		switch (businessTypeEnum) {
		case NFT_VIP_MONTH:
		case NFT_VIP_SEASON:
		case NFT_VIP_YEAR: {
			return PayAttach.builder().benefitPackageId(Long.valueOf(businessOrder.getGoodsId())).build();
		}
		case NORMAL:
		case ROSE_MINT:
		case BUY_ASSET_1155:
		case C_TO_C:
		case ASSET_WITH_PHYSICAL: {
			long assetId = Long.valueOf(businessOrder.getGoodsId());
			AssetInfoResponse asset = iInnerService.infoWithAssetId(assetId);
			PayAttach payAttach = new PayAttach();
			payAttach.setAssetId(assetId);
			payAttach.setGoodsId(asset.getGoodsId());
			payAttach.setPurchaseNum(businessOrder.getPurchaseNum());
			if (Objects.equals(asset.getOwnerType(), OwnerTypeEnum.USER.code()) || Objects.equals(asset.getOwnerType(), OwnerTypeEnum.AGENT.code())) {
				payAttach.setC2C(true);
				BigDecimal sellerIncome;
				if (Objects.equals(asset.getSecondType(), SecondEnum.MINT_POWER.getCode())) {
					sellerIncome = businessOrder
							.getTotalPrice()
							.multiply(new BigDecimal(SPLIT_ACCOUNT_PERCENTAGE))
							.divide(BigDecimal.valueOf(100))
							.setScale(2, BigDecimal.ROUND_HALF_UP);
				} else {
					sellerIncome = businessOrder
							.getTotalPrice()
							.multiply(new BigDecimal(SECOND_TRADE_SPLIT_ACCOUNT_PERCENTAGE))
							.divide(BigDecimal.valueOf(100))
							.setScale(2, BigDecimal.ROUND_HALF_UP);
				}
				SplitAccountItem splitAccountItem = new SplitAccountItem(businessOrder.getSellerId(), sellerIncome.toPlainString(), SPLIT_ACCOUNT_PERCENTAGE);
				payAttach.setSplitAccountDetails(Arrays.asList(splitAccountItem));
			}
			return payAttach;
		}

		}
		return null;
	}

	private void handleFixPayCenterData(List<TblPayOrder> records) {
		for (TblPayOrder record : records) {
			PayCenterOrderStatusResponse orderStatusResponse = refreshPayOrderStatus(record.getPayOrderId(), String.valueOf(record.getAppUserId()), record
					.getOrderMoney(), record.getBusinessAttach());
			if (orderStatusResponse != null && Objects.equals(orderStatusResponse.getState(), 1)
					&& StringUtils.isNotBlank(orderStatusResponse.getThirdTradeNo())) {
				Long paySuccessTime = null;
				if (record.getPaySuccessTime() == null && StringUtils.isNotBlank(orderStatusResponse.getPaidTime())) {
					try {
						paySuccessTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(orderStatusResponse.getPaidTime()).getTime();
					} catch (ParseException e) {
						log.error("convert paidTime failed. paidTime:" + orderStatusResponse.getPaidTime());
					}
				}
				LambdaUpdateChainWrapper<TblPayOrder> update = new LambdaUpdateChainWrapper<>(iTblPayOrderService.getBaseMapper());
				update.eq(TblPayOrder::getPayOrderId, record.getPayOrderId()).set(TblPayOrder::getPayTradeNo, orderStatusResponse.getThirdTradeNo());
				if (paySuccessTime != null && record.getPaySuccessTime() == null) {
					update.set(TblPayOrder::getPaySuccessTime, paySuccessTime);
				}
				update.update();
				log.info("fixPayCenterData for payOrderId:{} set payTradeNo value:{}", record.getPayOrderId(), orderStatusResponse.getThirdTradeNo());
			}
		}
	}

}
